/*******************************************************************************
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
module dwt.ole.win32.variant;

 
private import dwt.dwt;


private import dwt.ole.win32.ole;
private import dwt.ole.win32.oleautomation;
private import dwt.internal.ole.win32.com;
private import dwt.internal.ole.win32.OAIDL;
private import dwt.internal.ole.win32.extras;
private import dwt.internal.converter;


/**
 *
 * A Variant is a generic OLE mechanism for passing data of different types via a common interface.
 *
 * <p>It is used within the OleAutomation object for getting a property, setting a property or invoking
 * a method on an OLE Control or OLE Document.
 *
 */

public class Variant
{
	private import std.c.windows.windows;
	private import std.c.windows.com;
	
	// A variant always takes up 16 bytes, no matter what you 
	// store in it. Objects, strings, and arrays are not physically 
	// stored in the Variant; in these cases, four bytes of the 
	// Variant are used to hold either an object reference, or a 
	// pointer to the string or array. The actual data are stored elsewhere.
	
	// <Shawn> use VARIANT.sizeof instead 
//	public static const int sizeof_tag = 16;
	private ushort type; // OLE.VT_* type
	
	private boolean 	boolData;
	private float   floatData;
	private int     intData;
	private short   shortData;
	private char[]  stringData;
	private void*   byRefPtr;
	private IDispatch dispatchData;
	private IUnknown unknownData;

/*
	private VARIANT	 theVariant;
	
	// <Shawn Liu> wrapper of VARIANT
	VARTYPE type() { return theVariant.vt; };
	void type(VARTYPE val) { theVariant.vt = val; }
	LONG intData()  { return theVariant.lVal; }
	void intData(LONG val) { return theVariant.lVal = val; }
	FLOAT floatData()  { return theVariant.fltVal; }
	void floatData(FLOAT val) { return theVariant.fltVal = val; }
	IDispatch dispatchData() { return theVariant.pdispVal; }
	void dispatchData(IDispatch val) { theVariant.pdispVal = val; }
	IUnknown unknownData() { return theVariant.punkVal; }
	void unknownData(IUnknown val) { theVariant.punkVal = val; }
	VARIANT_BOOL boolData() { return theVariant.boolVal; }
	void boolData(VARIANT_BOOL val) { theVariant.boolVal = val; }	
	SHORT shortData() { return theVariant.iVal; }
	void shortData(SHORT val) { theVariant.iVal = val; }
	LPVOID byRefPtr() {
		LPVOID address;
		OS.MoveMemory(&address, &theVariant + 8, 4);
		return address;
	}
	void byRefPtr(LPVOID ptr) {	OS.MoveMemory(&theVariant + 8, &ptr, 4); }
*/	
	
/**
 * Create an empty Variant object with type VT_EMPTY.
 * 
 * @since 2.0
 */	
public this(){
	type = COM.VT_EMPTY;
}

/**
 * Added by Shawn Liu
 */
public this(VARIANT* pData)
{
	setData(pData);
}

/**
 * Create a Variant object which represents a Java float as a VT_R4.
 *
 * @param val the Java float value that this Variant represents
 *
 */
public this(float val) {
	type = COM.VT_R4;
	floatData = val;
	
}
/**
 * Create a Variant object which represents a Java int as a VT_I4.
 *
 * @param val the Java int value that this Variant represents
 *
 */
 public this(int val) {
	type = COM.VT_I4;
	intData = val;
}
public this(uint val) {
	this(cast(int)val);
}
/**
 * Create a Variant object which contains a reference to the data being transferred.
 *
 * <p>When creating a VT_BYREF Variant, you must give the full Variant type 
 * including VT_BYREF such as
 * 
 * <pre><code>short byRefType = OLE.VT_BSTR | OLE.VT_BYREF</code></pre>.
 *
 * @param ptr a pointer to the data being transferred.
 * @param byRefType the type of the data being transferred such as OLE.VT_BSTR | OLE.VT_BYREF
 *
 */
public this(LPVOID ptr, ushort byRefType) {
	type = byRefType;
	byRefPtr = ptr;
}
/**
 * Create a Variant object which represents an _IDispatch interface as a VT_Dispatch.
 *
 * @param automation the OleAutomation object that this Variant represents
 * 
 */
public this(OleAutomation automation) {
	type = COM.VT_DISPATCH;
	dispatchData = automation.getAddress();
}
/**
 * Create a Variant object which represents an _IDispatch interface as a VT_Dispatch.
 * <p>The caller is expected to have appropriately invoked unknown.AddRef() before creating 
 * this Variant.
 * 
 * @since 2.0
 * 
 * @param idispatch the _IDispatch object that this Variant represents
 * 
 */
public this(IDispatch idispatch) {
	type = COM.VT_DISPATCH;
	dispatchData = idispatch;
}
/**
 * Create a Variant object which represents an IUnknown interface as a VT_UNKNOWN.
 *
 * <p>The caller is expected to have appropriately invoked unknown.AddRef() before creating 
 * this Variant.
 *
 * @param unknown the IUnknown object that this Variant represents
 *
 */
public this(IUnknown unknown) {
	type = COM.VT_UNKNOWN;
	unknownData = unknown;
}
/**
 * Create a Variant object which represents a Java String as a VT_BSTR.
 *
 * @param string the Java String value that this Variant represents
 *
 */
public this(char[] string) {
	type = COM.VT_BSTR;
	stringData = string;
	
}
/**
 * Create a Variant object which represents a Java short as a VT_I2.
 *
 * @param val the Java short value that this Variant represents
 *
 */
public this(short val) {
	type = COM.VT_I2;
	shortData = val;
}
/**
 * Create a Variant object which represents a Java boolean as a VT_BOOL.
 *
 * @param val the Java boolean value that this Variant represents
 *
 */
public this(bool val) {
	type = COM.VT_BOOL;
	boolData = val ? COM.VARIANT_TRUE : COM.VARIANT_FALSE;
}

/**
 * Calling dispose will release resources associated with this Variant.
 * If the resource is an _IDispatch or IUnknown interface, Release will be called.
 * If the resource is a ByRef pointer, nothing is released.
 * 
 * @since 2.1
 */
public void dispose() {
	if ((type & COM.VT_BYREF) == COM.VT_BYREF) {
		return;
	}
		
	switch (type) {
		case COM.VT_EMPTY :
		case COM.VT_BOOL :
		case COM.VT_R4 :
		case COM.VT_I4 :
		case COM.VT_I2 :
		case COM.VT_BSTR :
			break;
		case COM.VT_DISPATCH :
			dispatchData.Release();
			break;
		case COM.VT_UNKNOWN :
			unknownData.Release();
			break;
		default : break;
	}
	
}
/**
 * Returns the OleAutomation object represented by this Variant.
 *
 * <p>If this Variant does not contain an OleAutomation object, an attempt is made to
 * coerce the Variant type into an OleAutomation object.  If this fails, an error is
 * thrown.  Note that OleAutomation objects must be disposed when no longer
 * needed.
 *
 * @return the OleAutomation object represented by this Variant
 *
 * @exception SWTError
 *		ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into an OleAutomation object
 */
public OleAutomation getAutomation() {
	if (type == COM.VT_EMPTY) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
	}
	if (type == COM.VT_DISPATCH) {
		return new OleAutomation(dispatchData);
	}
	// try to coerce the value to the desired type
	VARIANT oldPtr, newPtr;
	try {
		getData(&oldPtr);
		HRESULT result = COM.VariantChangeType(&newPtr, &oldPtr, 0, COM.VT_DISPATCH);
		if (result != COM.S_OK)
			OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
		Variant autoVar = new Variant();
		autoVar.setData(&newPtr);
		return autoVar.getAutomation();
	} finally {
		COM.VariantClear(&oldPtr);
		COM.VariantClear(&newPtr); // Note: This must absolutely be done AFTER the 
		                          // OleAutomation object is created as Variant Clear 
		                          // will result in a Release being performed on the 
		                          // Dispatch object
	}
	// return null;
}
/**
 * Returns the _IDispatch object represented by this Variant.
 *
 * <p>If this Variant does not contain an _IDispatch object, an attempt is made to
 * coerce the Variant type into an IDIspatch object.  If this fails, an error is
 * thrown.
 *
 * @since 2.0
 * 
 * @return the _IDispatch object represented by this Variant
 *
 * @exception SWTError
 *		ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into an _IDispatch object
 */
public IDispatch getDispatch() {
	if (type == COM.VT_EMPTY) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
	}
	
	if (type == COM.VT_DISPATCH) {
		return dispatchData;
	}
	// try to coerce the value to the desired type
	VARIANT oldPtr, newPtr;
	try {
		getData(&oldPtr);
		HRESULT result = COM.VariantChangeType(&newPtr, &oldPtr, 0, COM.VT_DISPATCH);
		if (result != COM.S_OK)
			OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
		Variant autoVar = new Variant();
		autoVar.setData(&newPtr);
		return autoVar.getDispatch();
	} finally {
		COM.VariantClear(&oldPtr);
		COM.VariantClear(&newPtr); // Note: This must absolutely be done AFTER the 
		                          // OleAutomation object is created as Variant Clear 
		                          // will result in a Release being performed on the 
		                          // Dispatch object
	}
	// return null;
}
/**
 * Returns the Java boolean represented by this Variant.
 *
 * <p>If this Variant does not contain a Java boolean, an attempt is made to
 * coerce the Variant type into a Java boolean.  If this fails, an error is thrown.
 *
 * @return the Java boolean represented by this Variant
 *
 * @exception SWTError
 * <ul><li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into a boolean</ul>
 *
 */
public boolean getBoolean() {
	if (type == COM.VT_EMPTY) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
	}
	if (type == COM.VT_BOOL) {
		return boolData;
	}

	// try to coerce the value to the desired type
	VARIANT oldPtr, newPtr;
	try {
		getData(&oldPtr);
		HRESULT result = COM.VariantChangeType(&newPtr, &oldPtr, 0, COM.VT_BOOL);
		if (result != COM.S_OK)
			OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
		Variant boolVar = new Variant();
		boolVar.setData(&newPtr);
		return boolVar.getBoolean();
	} finally {
		COM.VariantClear(&oldPtr);
		COM.VariantClear(&newPtr);
	}
	// return boolData;
}
/**
 * Returns a pointer to the referenced data represented by this Variant.
 *
 * <p>If this Variant does not contain a reference to data, zero is returned.
 *
 * @return a pointer to the referenced data represented by this Variant or 0
 *
 */
public void* getByRef() {
	if (type == COM.VT_EMPTY) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
	}
	if ((type & COM.VT_BYREF)== COM.VT_BYREF) {
		return byRefPtr;
	}
		
	return null;
}

// pass the content from this Variant to VARIANT*
void getData(VARIANT* pData){
	
	assert(pData);
	
	COM.VariantInit(pData);
	
	// set type 
	pData.vt = type;
	
	if ((type & COM.VT_BYREF) == COM.VT_BYREF) {
		COM.MoveMemory(pData + 8, &byRefPtr, 4);
		return;
	}
	
	switch (type) {
		case COM.VT_EMPTY :
			break;
		case COM.VT_BOOL :
			short bData = (boolData) ? COM.VARIANT_TRUE : COM.VARIANT_FALSE;
			pData.boolVal = bData;
			break;
		case COM.VT_R4 :
			pData.fltVal = floatData;
			break;
		case COM.VT_I4 :
			pData.lVal = intData;
			break;
		case COM.VT_DISPATCH :
			dispatchData.AddRef();
			pData.pdispVal = dispatchData;
			break;
		case COM.VT_UNKNOWN :
			unknownData.AddRef();
			pData.punkVal = unknownData;
			break;
		case COM.VT_I2 :
			pData.iVal = shortData;
			break;
		case COM.VT_BSTR :
			wchar* data = Converter.StrToWCHARz(stringData);
			BSTR bstr = COM.SysAllocString(data);
			pData.bstrVal = bstr;
			break;
	
		default :
			OLE.error (__FILE__, __LINE__, DWT.ERROR_NOT_IMPLEMENTED);
	}
	
}
/**
 * Returns the Java float represented by this Variant.
 *
 * <p>If this Variant does not contain a Java float, an attempt is made to
 * coerce the Variant type into a Java float.  If this fails, an error is thrown.
 *
 * @return the Java float represented by this Variant
 *
 * @exception SWTError
 * <ul><li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into a float</ul>
 */
public float getFloat() {
	if (type == COM.VT_EMPTY) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
	}
	if (type == COM.VT_R4) {
		return floatData;
	}

	// try to coerce the value to the desired type
	VARIANT oldPtr, newPtr;
	try {
		getData(&oldPtr);
		HRESULT result = COM.VariantChangeType(&newPtr, &oldPtr, 0, COM.VT_R4);
		if (result != COM.S_OK)
			OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
		Variant floatVar = new Variant();
		floatVar.setData(&newPtr);
		return floatVar.getFloat();
	} finally {
		COM.VariantClear(&oldPtr);
		COM.VariantClear(&newPtr);
	}
	// return 0;
	
}
/**
 * Returns the Java int represented by this Variant.
 *
 * <p>If this Variant does not contain a Java int, an attempt is made to
 * coerce the Variant type into a Java int.  If this fails, an error is thrown.
 *
 * @return the Java int represented by this Variant
 *
 * @exception SWTError
 * <ul><li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into a int</ul>
 */
public int getInt() {
	if (type == COM.VT_EMPTY) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
	}
	if (type == COM.VT_I4) {
		return intData;
	}
		
	// try to coerce the value to the desired type
	VARIANT oldPtr, newPtr;
	try {
		getData(&oldPtr);
		HRESULT result = COM.VariantChangeType(&newPtr, &oldPtr, 0, COM.VT_I4);
		if (result != COM.S_OK)
			OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
		Variant intVar = new Variant();
		intVar.setData(&newPtr);
		return intVar.getInt();
	} finally {
		COM.VariantClear(&oldPtr);
		COM.VariantClear(&newPtr);
	}
	// return 0;
}
/**
 * Returns the Java short represented by this Variant.
 *
 * <p>If this Variant does not contain a Java short, an attempt is made to
 * coerce the Variant type into a Java short.  If this fails, an error is thrown.
 *
 * @return the Java short represented by this Variant
 *
 * @exception SWTError
 * <ul><li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into a short</ul>
 */
public short getShort() {
	if (type == COM.VT_EMPTY) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
	}
	if (type == COM.VT_I2) {
		return shortData;
	}
		
	// try to coerce the value to the desired type
	VARIANT oldPtr, newPtr;
	try {
		getData(&oldPtr);
		HRESULT result = COM.VariantChangeType(&newPtr, &oldPtr, 0, COM.VT_I2);
		if (result != COM.S_OK)
			OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
		Variant shortVar = new Variant();
		shortVar.setData(&newPtr);
		return shortVar.getShort();
	} finally {
		COM.VariantClear(&oldPtr);
		COM.VariantClear(&newPtr);
	}
	// return 0;
}
/**
 * Returns the Java String represented by this Variant.
 *
 * <p>If this Variant does not contain a Java String, an attempt is made to
 * coerce the Variant type into a Java String.  If this fails, an error is thrown.
 *
 * @return the Java String represented by this Variant
 *
 * @exception SWTError
 * <ul><li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into a String</ul>
 */
public char[] getString() {
	if (type == COM.VT_EMPTY) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
	}
	if (type == COM.VT_BSTR) {
		return (stringData);
	}

	// try to coerce the value to the desired type
	VARIANT oldPtr, newPtr;
	try {
		getData(&oldPtr);
		HRESULT result = COM.VariantChangeType(&newPtr, &oldPtr, 0, COM.VT_BSTR);
		if (result != COM.S_OK)
			OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);

		Variant stringVar = new Variant();
		stringVar.setData(&newPtr);
		return stringVar.getString();
			
	} finally {
		COM.VariantClear(&oldPtr);
		COM.VariantClear(&newPtr);
	}
	// return null;
}
/**
 * Returns the ytpe of the variant type.  This will be an OLE.VT_* value or
 * a bitwise combination of OLE.VT_* values as in the case of 
 * OLE.VT_BSTR | OLE.VT_BYREF.
 * 
 * @return the type of the variant data
 * 
 * @since 2.0
 */
public ushort getType() {
	return type;
}
/**
 * Returns the IUnknown object represented by this Variant.
 *
 * <p>If this Variant does not contain an IUnknown object, an attempt is made to
 * coerce the Variant type into an IUnknown object.  If this fails, an error is
 * thrown.
 *
 * @return the IUnknown object represented by this Variant
 *
 * @exception SWTError
 * <ul><li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into 
 *			an IUnknown object</ul>
 */
public IUnknown getUnknown() {
	if (type == COM.VT_EMPTY) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
	}
	if (type == COM.VT_UNKNOWN) {
		return unknownData;
	}

	// try to coerce the value to the desired type
	VARIANT oldPtr, newPtr;
	try {
		getData(&oldPtr);
		HRESULT result = COM.VariantChangeType(&newPtr, &oldPtr, 0, COM.VT_UNKNOWN);
		if (result != COM.S_OK)
			OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
		Variant unknownVar = new Variant();
		unknownVar.setData(&newPtr);
		return unknownVar.getUnknown();
	} finally {
		COM.VariantClear(&oldPtr);
		COM.VariantClear(&newPtr); // Note: This must absolutely be done AFTER the 
		                          // IUnknown object is created as Variant Clear 
		                          // will result in a Release being performed on the 
		                          // Dispatch object
	}
	// return null;
}


/**
 * Update the by reference value of this variant with a new boolean value.
 * 
 * @param val the new boolean value
 * 
 * @exception SWTError
 * <ul><li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant is not 
 *			a (VT_BYREF | VT_BOOL) object</ul>
 *
 * @since 2.1
 */
public void setByRef(bool val) {
	if ((type & COM.VT_BYREF) == 0 || (type & COM.VT_BOOL) == 0) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE);
	}
	
	// actually short 
	VARIANT_BOOL value = val ? COM.VARIANT_TRUE : COM.VARIANT_FALSE;
	COM.MoveMemory(byRefPtr, &value, 2);
}
/**
 * Update the by reference value of this variant with a new float value.
 * 
 * @param val the new float value
 * 
 * @exception SWTError
 * <ul><li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant is not 
 *			a (VT_BYREF | VT_R4) object</ul>
 *
 * @since 2.1
 */
public void setByRef(float val) {
	if ((type & COM.VT_BYREF) == 0 || (type & COM.VT_R4) == 0) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE);
	}
	
	OS.MoveMemory(byRefPtr, &val, 4);	
}
/**
 * Update the by reference value of this variant with a new integer value.
 * 
 * @param val the new integer value
 * 
 * @exception SWTError
 * <ul><li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant is not 
 *			a (VT_BYREF | VT_I4) object</ul>
 *
 * @since 2.1
 */
public void setByRef(int val) {
	if ((type & COM.VT_BYREF) == 0 || (type & COM.VT_I4) == 0) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE);
	}
	COM.MoveMemory(byRefPtr, &val, 4);
}
/**
 * Update the by reference value of this variant with a new short value.
 * 
 * @param val the new short value
 * 
 * @exception SWTError
 * <ul><li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant is not 
 *			a (VT_BYREF | VT_I2) object</ul>
 *
 * @since 2.1
 */
public void setByRef(short val) {
	if ((type & COM.VT_BYREF) == 0 || (type & COM.VT_I2) == 0) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE);
	}
	COM.MoveMemory(byRefPtr, &val, 2);
}

// fill this Variant's contents with the VARIANT*
void setData(VARIANT* pData){
	
	assert(pData);
	if (pData is null) OLE.error(__FILE__, __LINE__, OLE.ERROR_INVALID_ARGUMENT);
	
	type = pData.vt;

	if ((type & COM.VT_BYREF) == COM.VT_BYREF) {
		void* newByRefPtr;
		OS.MoveMemory(&newByRefPtr, pData + 8, 4);
		byRefPtr = newByRefPtr;
		return;
	}
	
	switch (type) {
		case COM.VT_EMPTY :
			break;
		case COM.VT_BOOL :
			boolData = (pData.boolVal != COM.VARIANT_FALSE) ? true : false;
			break;
		case COM.VT_R4 :
			floatData = pData.fltVal;
			break;
		case COM.VT_I4 :
			intData = pData.lVal;
			break;
		case COM.VT_DISPATCH : {
			if (pData.pdispVal is null) {
				type = COM.VT_EMPTY;
				break;
			}
			dispatchData = pData.pdispVal;
			dispatchData.AddRef();
			break;
		}
		case COM.VT_UNKNOWN : {
			if (pData.punkVal is null) {
				type = COM.VT_EMPTY;
				break;
			}
			unknownData = pData.punkVal;
			unknownData.AddRef();
			break;
		}
		case COM.VT_I2 :
			shortData = pData.iVal;
			break;
		case COM.VT_BSTR :
			// get the address of the memory in which the string resides
			BSTR bstr = pData.bstrVal;
			if (bstr is null ) {
				type = COM.VT_EMPTY;
				break;
			}
			// Get the size of the string from the OS - the size is expressed in number
			// of bytes - each unicode character is 2 bytes.
			int size = COM.SysStringByteLen(bstr);
			if (size > 0){
				// get the unicode character array from the global memory and create a String
				size = (size + 1) /2; // add one to avoid rounding errors
				stringData = Converter.WCHARzToStr(bstr, size);
			} else {
				stringData = ""; //$NON-NLS-1$
			}
			break;
	
		default :
			// try coercing it into one of the known forms
			VARIANT newPData;
			if (COM.VariantChangeType(&newPData, pData, 0, COM.VT_R4) == COM.S_OK) {
				setData(&newPData);
			} else if (COM.VariantChangeType(&newPData, pData, 0, COM.VT_I4) == COM.S_OK) {
				setData(&newPData);
			} else if (COM.VariantChangeType(&newPData, pData, 0, COM.VT_BSTR) == COM.S_OK) {
				setData(&newPData);
			}
			COM.VariantClear(&newPData);
			break;
	}
	
}

} // end of class Variant


/+

/**
 * 
 * VARIANT struct prototype moved from OAIDL.d to here
 */
 
// A variant always takes up 16 bytes, no matter what you 
// store in it. Objects, strings, and arrays are not physically 
// stored in the Variant; in these cases, four bytes of the 
// Variant are used to hold either an object reference, or a 
// pointer to the string or array. The actual data are stored elsewhere.

union n3_t {
    LONG          lVal;         /* VT_I4                */
    BYTE          bVal;         /* VT_UI1               */
    SHORT         iVal;         /* VT_I2                */
    FLOAT         fltVal;       /* VT_R4                */
    DOUBLE        dblVal;       /* VT_R8                */
    VARIANT_BOOL  boolVal;      /* VT_BOOL              */
    _VARIANT_BOOL bool;         /* (obsolete)           */
    SCODE         scode;        /* VT_ERROR             */
    CY            cyVal;        /* VT_CY                */
    DATE          date;         /* VT_DATE              */
    BSTR          bstrVal;      /* VT_BSTR              */
    IUnknown     punkVal;      /* VT_UNKNOWN           */
    IDispatch    pdispVal;     /* VT_DISPATCH          */
    SAFEARRAY *   parray;       /* VT_ARRAY             */
    BYTE *        pbVal;        /* VT_BYREF|VT_UI1      */
    SHORT *       piVal;        /* VT_BYREF|VT_I2       */
    LONG *        plVal;        /* VT_BYREF|VT_I4       */
    FLOAT *       pfltVal;      /* VT_BYREF|VT_R4       */
    DOUBLE *      pdblVal;      /* VT_BYREF|VT_R8       */
    VARIANT_BOOL *pboolVal;     /* VT_BYREF|VT_BOOL     */
    _VARIANT_BOOL *pbool;       /* (obsolete)           */
    SCODE *       pscode;       /* VT_BYREF|VT_ERROR    */
    CY *          pcyVal;       /* VT_BYREF|VT_CY       */
    DATE *        pdate;        /* VT_BYREF|VT_DATE     */
    BSTR *        pbstrVal;     /* VT_BYREF|VT_BSTR     */
    IUnknown *   ppunkVal;     /* VT_BYREF|VT_UNKNOWN  */
    IDispatch *   ppdispVal;    /* VT_BYREF|VT_DISPATCH */
    SAFEARRAY **  pparray;      /* VT_BYREF|VT_ARRAY    */
    VARIANT *     pvarVal;      /* VT_BYREF|VT_VARIANT  */
    PVOID         byref;        /* Generic ByRef        */
    CHAR          cVal;         /* VT_I1                */
    USHORT        uiVal;        /* VT_UI2               */
    ULONG         ulVal;        /* VT_UI4               */
    INT           intVal;       /* VT_INT               */
    UINT          uintVal;      /* VT_UINT              */
    DECIMAL *     pdecVal;      /* VT_BYREF|VT_DECIMAL  */
    CHAR *        pcVal;        /* VT_BYREF|VT_I1       */
    USHORT *      puiVal;       /* VT_BYREF|VT_UI2      */
    ULONG *       pulVal;       /* VT_BYREF|VT_UI4      */
    INT *         pintVal;      /* VT_BYREF|VT_INT      */
    UINT *        puintVal;     /* VT_BYREF|VT_UINT     */
	brecVal_t brecVal;         /* VT_RECORD            */
}

struct n2_t {
    VARTYPE vt;
    WORD    wReserved1;
    WORD    wReserved2;
    WORD    wReserved3;
    n3_t n3;
};
union n1_t {
	n2_t n2;
    DECIMAL decVal;
};

struct VARIANT {
	n1_t n1;

	VARTYPE vt() { return n1.n2.vt; };
	void vt(VARTYPE val) { n1.n2.vt = val; }
	LONG lVal()  { return n1.n2.n3.lVal; }
	void lVal(LONG val) { return n1.n2.n3.lVal = val; }
	FLOAT fltVal()  { return n1.n2.n3.fltVal; }
	void fltVal(FLOAT val) { return n1.n2.n3.fltVal = val; }
	IDispatch pdispVal() { return n1.n2.n3.pdispVal; }
	void pdispVal(IDispatch val) { n1.n2.n3.pdispVal = val; }
	IUnknown punkVal() { return n1.n2.n3.punkVal; }
	void punkVal(IUnknown val) { n1.n2.n3.punkVal = val; }
	VARIANT_BOOL boolVal() { return n1.n2.n3.boolVal; }
	void boolVal(VARIANT_BOOL val) { n1.n2.n3.boolVal = val; }
	SHORT iVal() { return n1.n2.n3.iVal; }
	void iVal(SHORT val) { n1.n2.n3.iVal = val; }
	BSTR bstrVal() { return n1.n2.n3.bstrVal; }
	void bstrVal(BSTR val) { n1.n2.n3.bstrVal = val; }

	
/**
 * Create an empty VARIANT struct with type VT_EMPTY.
 * 
 * @since 2.0
 */	
public static VARIANT opCall(){
	VARIANT theVariant;
	theVariant.vt = COM.VT_EMPTY;
	return theVariant;
}
/**
 * Create a VARIANT struct which represents a Java float as a VT_R4.
 *
 * @param val the Java float value that this Variant represents
 *
 */
public static VARIANT opCall(float val) {
	VARIANT theVariant;
	theVariant.vt = COM.VT_R4;
	theVariant.fltVal = val;
	return theVariant;
}
/**
 * Create a VARIANT struct which represents a Java int as a VT_I4.
 *
 * @param val the Java int value that this Variant represents
 *
 */
public static VARIANT opCall(int val) {
	VARIANT theVariant;
	theVariant.vt = COM.VT_I4;
	theVariant.lVal = val;
	return theVariant;
}
public static VARIANT opCall(uint val) {
	return VARIANT(cast(int)val);
}
/**
 * Create a VARIANT struct which contains a reference to the data being transferred.
 *
 * <p>When creating a VT_BYREF Variant, you must give the full Variant type 
 * including VT_BYREF such as
 * 
 * <pre><code>short byRefType = OLE.VT_BSTR | OLE.VT_BYREF</code></pre>.
 *
 * @param ptr a pointer to the data being transferred.
 * @param byRefType the type of the data being transferred such as OLE.VT_BSTR | OLE.VT_BYREF
 *
 */
public static VARIANT opCall(LPVOID ptr, ushort byRefType) {
	VARIANT theVariant;
	// make sure the VT_BYREF is applied
	theVariant.vt = cast(WORD)(byRefType|COM.VT_BYREF);
	// TODO:
	OS.MoveMemory(&theVariant + 8, &ptr, 4);
//	byRefPtr = ptr;
	return theVariant;
}
/**
 * Create a VARIANT struct which represents an _IDispatch interface as a VT_Dispatch.
 *
 * @param automation the OleAutomation object that this Variant represents
 * 
 */
public static VARIANT opCall(OleAutomation automation) {
	VARIANT theVariant;
	theVariant.vt = COM.VT_DISPATCH;
	theVariant.pdispVal = automation.getAddress();
	return theVariant;
}
/**
 * Create a VARIANT struct which represents an _IDispatch interface as a VT_Dispatch.
 * <p>The caller is expected to have appropriately invoked unknown.AddRef() before creating 
 * this Variant.
 * 
 * @since 2.0
 * 
 * @param idispatch the _IDispatch object that this Variant represents
 * 
 */
public static VARIANT opCall(IDispatch idispatch) {
	VARIANT theVariant;
	theVariant.vt = COM.VT_DISPATCH;
	theVariant.pdispVal = idispatch;
	return theVariant;
}
/**
 * Create a VARIANT struct which represents an IUnknown interface as a VT_UNKNOWN.
 *
 * <p>The caller is expected to have appropriately invoked unknown.AddRef() before creating 
 * this Variant.
 *
 * @param unknown the IUnknown object that this Variant represents
 *
 */
public static VARIANT opCall(IUnknown unknown) {
	VARIANT theVariant;
	theVariant.vt = COM.VT_UNKNOWN;
	theVariant.punkVal = unknown;
	return theVariant;
}
/**
 * Create a VARIANT struct which represents a Java String as a VT_BSTR.
 *
 * @param string the Java String value that this Variant represents
 *
 */
public static VARIANT opCall(char[] string) {
	return VARIANT(string[]);
}

// <Shawn> remember to call dispose() or VariantClear() to release the memory 
public static VARIANT opCall(char[] string) {
	VARIANT theVariant;
	theVariant.vt = COM.VT_BSTR;
	wchar* data = Converter.StrToWCHARz(string);
	BSTR ptr = COM.SysAllocString(data);
	theVariant.n1.n2.n3.bstrVal = ptr;
		
	return theVariant;
	
}
/**
 * Create a VARIANT struct which represents a Java short as a VT_I2.
 *
 * @param val the Java short value that this Variant represents
 *
 */
public static VARIANT opCall(short val) {
	VARIANT theVariant;
	theVariant.vt = COM.VT_I2;
	theVariant.iVal = val;
	return theVariant;
}
/**
 * Create a VARIANT struct which represents a Java boolean as a VT_BOOL.
 *
 * @param val the Java boolean value that this Variant represents
 *
 */
public static VARIANT opCall(bool val) {
	VARIANT theVariant;
	theVariant.vt = COM.VT_BOOL;
	theVariant.boolVal = val ? COM.VARIANT_TRUE : COM.VARIANT_FALSE;
	return theVariant;
}

/**
 * Calling dispose will release resources associated with this Variant.
 * If the resource is an IDispatch or IUnknown interface, Release will be
 * called. If the resource is a ByRef pointer, nothing is released.
 * 
 * @since 2.1
 */
public void dispose() {
	
	// <Shawn> just call COM.VariantClear() as well ???
	
	if ((vt & COM.VT_BYREF) == COM.VT_BYREF) {
		return;
	}
		
	switch (vt) {
		case COM.VT_EMPTY :
		case COM.VT_BOOL :
		case COM.VT_R4 :
		case COM.VT_I4 :
		case COM.VT_I2 :
			break;
		case COM.VT_DISPATCH :
			pdispVal.Release();
			break;
		case COM.VT_UNKNOWN :
			punkVal.Release();
			break;
		case COM.VT_BSTR :
			// TODO: do we need this ??
			COM.SysFreeString(n1.n2.n3.bstrVal);
			break;	
		default : break;
	}
	
}
/**
 * Returns the OleAutomation object represented by this Variant.
 *
 * <p>If this Variant does not contain an OleAutomation object, an attempt is made to
 * coerce the Variant type into an OleAutomation object.  If this fails, an error is
 * thrown.  Note that OleAutomation objects must be disposed when no longer
 * needed.
 *
 * @return the OleAutomation object represented by this Variant
 *
 * @exception SWTError
 *		ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into an OleAutomation object
 */
public OleAutomation getAutomation() {
	if (vt == COM.VT_EMPTY) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
	}
	if (vt == COM.VT_DISPATCH) {
		return new OleAutomation(pdispVal);
	}
	// try to coerce the value to the desired type
//	void* oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof_tag);
//	void* newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof_tag);
	VARIANT newPtr;
	try {
		HRESULT result = COM.VariantChangeType(&newPtr, this, 0, COM.VT_DISPATCH);
		if (result != COM.S_OK)
			OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
		return newPtr.getAutomation();
	} finally {
		COM.VariantClear(&newPtr); // Note: This must absolutely be done AFTER the 
		                          // OleAutomation object is created as Variant Clear 
		                          // will result in a Release being performed on the 
		                          // Dispatch object
//		OS.GlobalFree(newPtr);
	}
	return null;
}
/**
 * Returns the _IDispatch object represented by this Variant.
 *
 * <p>If this Variant does not contain an _IDispatch object, an attempt is made to
 * coerce the Variant type into an IDIspatch object.  If this fails, an error is
 * thrown.
 *
 * @since 2.0
 * 
 * @return the _IDispatch object represented by this Variant
 *
 * @exception SWTError
 *		ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into an _IDispatch object
 */
public IDispatch getDispatch() {
	if (vt == COM.VT_EMPTY) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
	}
	
	if (vt == COM.VT_DISPATCH) {
		return pdispVal;
	}
	// try to coerce the value to the desired type
//	void* oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof_tag);
//	void* newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof_tag);
	VARIANT newPtr;
	try {
		HRESULT result = COM.VariantChangeType(&newPtr, this, 0, COM.VT_DISPATCH);
		if (result != COM.S_OK)
			OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
		return newPtr.getDispatch();
	} finally {
//		OS.GlobalFree(oldPtr);
		COM.VariantClear(&newPtr); // Note: This must absolutely be done AFTER the 
		                          // OleAutomation object is created as Variant Clear 
		                          // will result in a Release being performed on the 
		                          // Dispatch object
//		OS.GlobalFree(newPtr);
	}
	return null;
}
/**
 * Returns the Java boolean represented by this Variant.
 *
 * <p>If this Variant does not contain a Java boolean, an attempt is made to
 * coerce the Variant type into a Java boolean.  If this fails, an error is thrown.
 *
 * @return the Java boolean represented by this Variant
 *
 * @exception SWTError
 * <ul><li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into a boolean</ul>
 *
 */
public boolean getBoolean() {
	if (vt == COM.VT_EMPTY) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
	}
	if (vt == COM.VT_BOOL) {
		return boolVal;
	}

	// try to coerce the value to the desired type
//	void* oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof_tag);
//	void* newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof_tag);
	VARIANT newPtr;
	try {
		HRESULT result = COM.VariantChangeType(&newPtr, this, 0, COM.VT_BOOL);
		if (result != COM.S_OK)
			OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
		return newPtr.getBoolean();
	} finally {
//		COM.VariantClear(&oldPtr);
//		OS.GlobalFree(oldPtr);
		COM.VariantClear(&newPtr);
//		OS.GlobalFree(newPtr);
	}
	return boolVal;
}
/**
 * Returns a pointer to the referenced data represented by this Variant.
 *
 * <p>If this Variant does not contain a reference to data, zero is returned.
 *
 * @return a pointer to the referenced data represented by this Variant or 0
 *
 */
public void* getByRef() {
	if (vt == COM.VT_EMPTY) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
	}
	if ((vt & COM.VT_BYREF)== COM.VT_BYREF) {
		return cast(void*)n1.n2.n3.plVal;
	}
		
	return null;
}
void getData(VARIANT* pData){
	
	assert(pData);
	
	// <Shawn> Note : If this VARIANT is a VT_BSTR, a copy of the string is made. 
	// If this VARIANT is a VT_ARRAY, the entire array is copied. 
	// If this VARIANT is a VT_DISPATCH or VT_UNKNOWN, AddRef is called to increment the object's reference count.

	COM.VariantCopy(pData, this);
}

/**
 * Returns the Java float represented by this Variant.
 *
 * <p>If this Variant does not contain a Java float, an attempt is made to
 * coerce the Variant type into a Java float.  If this fails, an error is thrown.
 *
 * @return the Java float represented by this Variant
 *
 * @exception SWTError
 * <ul><li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into a float</ul>
 */
public float getFloat() {
	if (vt == COM.VT_EMPTY) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
	}
	if (vt == COM.VT_R4) {
		return fltVal;
	}

	// try to coerce the value to the desired type
	VARIANT newPtr;
	try {
		HRESULT result = COM.VariantChangeType(&newPtr, this, 0, COM.VT_R4);
		if (result != COM.S_OK)
			OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
		return newPtr.getFloat();
	} finally {
		COM.VariantClear(&newPtr);
	}
	return 0;
	
}
/**
 * Returns the Java int represented by this Variant.
 *
 * <p>If this Variant does not contain a Java int, an attempt is made to
 * coerce the Variant type into a Java int.  If this fails, an error is thrown.
 *
 * @return the Java int represented by this Variant
 *
 * @exception SWTError
 * <ul><li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into a int</ul>
 */
public int getInt() {
	if (vt == COM.VT_EMPTY) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
	}
	if (vt == COM.VT_I4) {
		return lVal;
	}
		
	// try to coerce the value to the desired type
//	void* oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof_tag);
//	void* newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof_tag);
	VARIANT newPtr;
	try {
		HRESULT result = COM.VariantChangeType(&newPtr, this, 0, COM.VT_I4);
		if (result != COM.S_OK)
			OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
		return newPtr.getInt();
	} finally {
//		COM.VariantClear(&oldPtr);
//		OS.GlobalFree(oldPtr);
		COM.VariantClear(&newPtr);
//		OS.GlobalFree(newPtr);
	}
	return 0;
}
/**
 * Returns the Java short represented by this Variant.
 *
 * <p>If this Variant does not contain a Java short, an attempt is made to
 * coerce the Variant type into a Java short.  If this fails, an error is thrown.
 *
 * @return the Java short represented by this Variant
 *
 * @exception SWTError
 * <ul><li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into a short</ul>
 */
public short getShort() {
	if (vt == COM.VT_EMPTY) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
	}
	if (vt == COM.VT_I2) {
		return iVal;
	}
		
	// try to coerce the value to the desired type
//	void* oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof_tag);
//	void* newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof_tag);
	VARIANT newPtr;
	try {
		HRESULT result = COM.VariantChangeType(&newPtr, this, 0, COM.VT_I2);
		if (result != COM.S_OK)
			OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
		return newPtr.getShort();
	} finally {
//		COM.VariantClear(&oldPtr);
//		OS.GlobalFree(oldPtr);
		COM.VariantClear(&newPtr);
//		OS.GlobalFree(newPtr);
	}
	return 0;
}
/**
 * Returns the Java String represented by this Variant.
 *
 * <p>If this Variant does not contain a Java String, an attempt is made to
 * coerce the Variant type into a Java String.  If this fails, an error is thrown.
 *
 * @return the Java String represented by this Variant
 *
 * @exception SWTError
 * <ul><li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into a String</ul>
 */

 
public char[] getString() {
	if (vt == COM.VT_EMPTY) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
	}
	if (vt == COM.VT_BSTR) {
		// don't release the memory SysAllocString() allocated
		return Converter.WCHARzToStr(n1.n2.n3.bstrVal, -1);
	}

	// try to coerce the value to the desired type
//	void* oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof_tag);
//	void* newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof_tag);
	VARIANT newPtr;
	try {
		HRESULT result = COM.VariantChangeType(&newPtr, this, 0, COM.VT_BSTR);
		if (result != COM.S_OK)
			OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);

		return newPtr.getString();
			
	} finally {
		// TODO: do we need this ???
		COM.VariantClear(&newPtr);
	}
	return null;
}
/**
 * Returns the ytpe of the variant type.  This will be an OLE.VT_* value or
 * a bitwise combination of OLE.VT_* values as in the case of 
 * OLE.VT_BSTR | OLE.VT_BYREF.
 * 
 * @return the type of the variant data
 * 
 * @since 2.0
 */
public ushort getType() {
	return vt;
}
/**
 * Returns the IUnknown object represented by this Variant.
 *
 * <p>If this Variant does not contain an IUnknown object, an attempt is made to
 * coerce the Variant type into an IUnknown object.  If this fails, an error is
 * thrown.
 *
 * @return the IUnknown object represented by this Variant
 *
 * @exception SWTError
 * <ul><li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant can not be coerced into 
 *			an IUnknown object</ul>
 */
public IUnknown getUnknown() {
	if (vt == COM.VT_EMPTY) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, -1);
	}
	if (vt == COM.VT_UNKNOWN) {
		return punkVal;
	}

	// try to coerce the value to the desired type
//	void* oldPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof_tag);
//	void* newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, sizeof_tag);
	VARIANT newPtr;
	try {
		HRESULT result = COM.VariantChangeType(&newPtr, this, 0, COM.VT_UNKNOWN);
		if (result != COM.S_OK)
			OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE, result);
		return newPtr.getUnknown();
	} finally {
//		COM.VariantClear(&oldPtr);
//		OS.GlobalFree(oldPtr);
		COM.VariantClear(&newPtr); // Note: This must absolutely be done AFTER the 
		                          // IUnknown object is created as Variant Clear 
		                          // will result in a Release being performed on the 
		                          // Dispatch object
//		OS.GlobalFree(newPtr);
	}
	return null;
}


/**
 * Update the by reference value of this variant with a new boolean value.
 * 
 * @param val the new boolean value
 * 
 * @exception SWTError
 * <ul><li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant is not 
 *			a (VT_BYREF | VT_BOOL) object</ul>
 *
 * @since 2.1
 */
public void setByRef(bool val) {
	if ((vt & COM.VT_BYREF) == 0 || (vt & COM.VT_BOOL) == 0) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE);
	}
	
	short value = val ? COM.VARIANT_TRUE : COM.VARIANT_FALSE;
	*(n1.n2.n3.pboolVal) = value;
}
/**
 * Update the by reference value of this variant with a new float value.
 * 
 * @param val the new float value
 * 
 * @exception SWTError
 * <ul><li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant is not 
 *			a (VT_BYREF | VT_R4) object</ul>
 *
 * @since 2.1
 */
public void setByRef(float val) {
	if ((vt & COM.VT_BYREF) == 0 || (vt & COM.VT_R4) == 0) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE);
	}
	*(n1.n2.n3.pfltVal) = val;	
}

/**
 * Update the by reference value of this variant with a new integer value.
 * 
 * @param val the new integer value
 * 
 * @exception SWTError
 * <ul><li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant is not 
 *			a (VT_BYREF | VT_I4) object</ul>
 *
 * @since 2.1
 */
public void setByRef(int val) {
	if ((vt & COM.VT_BYREF) == 0 || (vt & COM.VT_I4) == 0) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE);
	}
	*(n1.n2.n3.plVal) = val;
}
/**
 * Update the by reference value of this variant with a new short value.
 * 
 * @param val the new short value
 * 
 * @exception SWTError
 * <ul><li>ERROR_CANNOT_CHANGE_VARIANT_TYPE when type of Variant is not 
 *			a (VT_BYREF | VT_I2) object</ul>
 *
 * @since 2.1
 */
public void setByRef(short val) {
	if ((vt & COM.VT_BYREF) == 0 || (vt & COM.VT_I2) == 0) {
		OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CHANGE_VARIANT_TYPE);
	}
	*(n1.n2.n3.piVal) = val;
}

void setData(VARIANT* pData){
	assert(pData);
	// if (pData is null) OLE.error(__FILE__, __LINE__, OLE.ERROR_INVALID_ARGUMENT);
	*this = *pData;
	
	switch(vt){
	case COM.VT_UNKNOWN :
		punkVal.AddRef();
		break;
	case COM.VT_DISPATCH :
		pdispVal.AddRef();
		break;
	case COM.VT_BSTR :
		// TODO:
		break;
	default:
		break;
	}
		
	/*
	COM.MoveMemory(&type, pData, 2);

	if ((type & COM.VT_BYREF) == COM.VT_BYREF) {
		int newByRefPtr;
		OS.MoveMemory(&newByRefPtr, pData + 8, 4);
		byRefPtr = newByRefPtr;
		return;
	}
	
	switch (type) {
		case COM.VT_EMPTY :
			break;
		case COM.VT_BOOL :
			short newBooleanData;
			COM.MoveMemory(&newBooleanData, pData + 8, 2);
			boolVal = (newBooleanData != COM.VARIANT_FALSE) ? true : false;
			break;
		case COM.VT_R4 :
			OS.MoveMemory(&fltVal, pData + 8, 4);
			break;
		case COM.VT_I4 :
			OS.MoveMemory(&intData, pData + 8, 4);
			break;
		case COM.VT_DISPATCH : {
			void* ppvObject;
			OS.MoveMemory(&ppvObject, pData + 8, 4);
			if (ppvObject is null) {
				type = COM.VT_EMPTY;
				break;
			}
			pdispVal = cast(IDispatch)(ppvObject);
			pdispVal.AddRef();
			break;
		}
		case COM.VT_UNKNOWN : {
			void* ppvObject;
			OS.MoveMemory(&ppvObject, pData + 8, 4);
			if (ppvObject is null) {
				type = COM.VT_EMPTY;
				break;
			}
			unknownData = cast(IUnknown)(ppvObject);
			unknownData.AddRef();
			break;
		}
		case COM.VT_I2 :
			COM.MoveMemory(&shortData, pData + 8, 2);
			break;
		case COM.VT_BSTR :
			// get the address of the memory in which the string resides
			wchar* hMem;
			OS.MoveMemory(&hMem, pData + 8, 4);
			if (hMem is null ) {
				type = COM.VT_EMPTY;
				break;
			}
			// Get the size of the string from the OS - the size is expressed in number
			// of bytes - each unicode character is 2 bytes.
			int size = COM.SysStringByteLen(hMem);
			if (size > 0){
				// get the unicode character array from the global memory and create a String
				size = (size + 1) /2; // add one to avoid rounding errors
				stringData = Convert.WCHARzToStr(hMem, size);
			} else {
				stringData = ""; //$NON-NLS-1$
			}
			break;
	
		default :
			// try coercing it into one of the known forms
//			void* newPData = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, Variant.sizeof_tag);
			VARIANT newPData;
			if (COM.VariantChangeType(&newPData, cast(VARIANT*)pData, 0, COM.VT_R4) == COM.S_OK) {
				setData(&newPData);
			} else if (COM.VariantChangeType(&newPData, cast(VARIANT*)pData, 0, COM.VT_I4) == COM.S_OK) {
				setData(&newPData);
			} else if (COM.VariantChangeType(&newPData, cast(VARIANT*)pData, 0, COM.VT_BSTR) == COM.S_OK) {
				setData(&newPData);
			}
			COM.VariantClear(&newPData);
//			OS.GlobalFree(newPData);
			break;
	}
	*/
}

} // end of struct VARIANT

+/